// encoding utf-8
#ifndef __QyGLObject__
#define __QyGLObject__

#include <QtCore/QVector>
#include <QtOpenGL>
#include <QyMath.h>

namespace QyGL {

/*! \brief Класс для хранения параметров (пространственные координаты, текстурные координаты, координаты нормали, цвет) вершин.
    \ingroup QyOpenGL
*/
class Vertex {
public:
    explicit Vertex( const QyMath::Point & p = QyMath::Point(), const QyMath::Point & c = QyMath::Point( 1, 1, 1 ),
        const QyMath::Point & tc = QyMath::Point(), const QyMath::Point & n = QyMath::Point( 1, 1, 1 ) )
        : pos(p), color(c), texCoord(tc), normal(n) {}

    QyMath::Point pos, //!< Пространственные координаты
        color, //!< Цвет
        texCoord, //!< Текстурные координаты
        normal; //!< Координаты нормали (вектор нормали)

};


typedef QVector<QyMath::Point> PointVector; //!< Вектор точек
typedef QVector<Vertex> VertexVector; //!< Вектор вершин

/*! \brief Класс для хранения параметров текстуры, и управления состоянием.
    \ingroup QyOpenGL
*/
class Texture {
public:
    //! Тип фильтрации
    enum Filter {
        Linear,        //!< Линейная
        Bilinear,    //!< Билинейная
        Trilinear,    //!< Триленейная
        Anisotropic    //!< Четырелине... ой, Анизотропная =)
    };
    explicit Texture( quint32 textureId = 0, qint32 target = GL_TEXTURE_2D )
        : p_textureId(textureId), p_target(target) {}

    quint32 textureId() const { return p_textureId; } //!< Идентификатор текстуры в контексте
    quint32 target() const { return p_target; } //!< Тип текстуры (1Д, 2Д, 3Д и т.д.)
    bool isValid() const { return p_textureId && p_target; } //!< Проверка валидности

    void bind(); //!< Установить текстуру как текущюю для текущего контекста
    void unbind(); //!< Установить нулевую текстуру для текущего контекста
    void setTexture( quint32 textureId = 0, qint32 target = GL_TEXTURE_2D )
        { p_textureId = textureId; p_target = target; } //!< Установить идентификатор текстуры и тип

    static void setFilter( qint32 filter, qint32 target = 0/*for all (1D, 2D, 3D)*/ ); //!< Установить тип фильтрации текстур
    static void setMaxAnisotropy( qreal maxAnisotropy ) { p_maxAnisotropy = maxAnisotropy; } //!< Установить максимальное значение для анизотропной фильтрации
    static qreal maxAnisotropy() { return p_maxAnisotropy; } //!< Максимальное значение для анизотропной фильтрации

private:
    quint32 p_textureId;
    qint32 p_target;

    static qreal p_maxAnisotropy;

};

/*! \brief Позволяет задав набор точек и тип примитивов, отрисовать их последовательно. Так-же есть возможность управления рисованием.
    \ingroup QyOpenGL
*/
class Object {
public:
    //! Параметры отрисовки
    enum PaintOption {
        Colors      = 1, //!< Отсылать цвет вершин на конвеер
        TexCoords   = 2, //!< Отсылать текстурнае координаты на конвеер
        Normals     = 4, //!< Отсылать координаты нормалей на конвеер
        Textured    = 8, //!< Применять тексуру к объекту
        All         = Colors|TexCoords|Normals|Textured //!< Все включено
    };
    explicit Object( const VertexVector & vertexes = VertexVector(), qint32 type = GL_POINTS,
        int paintFlags = All )
        : p_vertexes(vertexes), p_type(type), p_modifiyCount(1), p_paintFlags(paintFlags) {}
    virtual ~Object() {}

    VertexVector vertexes() const { return p_vertexes; } //!< Список вершин
    VertexVector & vertexesLink() { return p_vertexes; } //!< ссылка на список вершин
    qint32 type() const { return p_type; } //!< Тип примитива (GL_POINTS, GL_TRIANGLES, GL_QUADS ...)
    Texture texture() const { return p_texture; } //!< Текстура
    qint32 paintFlags() const { return p_paintFlags; } //!< Параметры отрисовки

    void setVertexes( const VertexVector & vertexes ) { p_vertexes = vertexes; p_modifiyCount ++; } //!< Установить список вершин
    void setType( qint32 type ) { p_type = type; p_modifiyCount ++; } //!< Установить тип примитивов
    void setTexture( const Texture & texture ) { p_texture = texture; } //!< Установить текстуру
    void setPaintFlags( qint32 paintFlags ) { p_paintFlags = paintFlags; } //!< Установить параметры отрисовки
    virtual void paint(); //!< Отрисовать
    virtual void paintOn( const QyMath::Point & pos ); //!< Отрисовать со смещением в заданную точку

protected:
    quint32 modifiyCount() const { return p_modifiyCount; } //!< Текущая модификация (для кэширования)

private:
    VertexVector p_vertexes; // вершины
    qint32 p_type; // тип
    quint32 p_modifiyCount, // модификация
        p_paintFlags; // параметры отрисовки
    Texture p_texture; // текстуры

    friend class ObjectCache;
};


/*! \brief Кэш объекта. Позволяет "записать" объект в список отображения. Список отображения будет автоматически обновляться в соответствии с изменениями в объекте.
    \ingroup QyOpenGL
*/
class ObjectCache {
public:
    explicit ObjectCache( Object * object = 0 ) : p_object(object), p_cache(0), p_modifiyCount(0) {}
    virtual ~ObjectCache() {}

    Object * object() const { return p_object; } //!< Кешируемый объект

    virtual void paint(); //!< Отрисовать
    virtual void paintOn( const QyMath::Point & pos ); //!< Отрисовать со смещением в заданную точку

protected:
    quint32 cache() const { return p_cache; } //!< идентификатор списка отображения
    quint32 modifiyCount() const { return p_modifiyCount; } //!< номер модификации объекта, сохраненного в кэше. Если этот номер при отрисовке не совпадет с номером обновления объекта, то объект будет перекэширован

private:
    Object * p_object;
    quint32 p_cache,
        p_modifiyCount;

};


};

#endif//__QyGLObject__
